class Dep {
	static uid = 0
	id = Dep.uid++
	static target: Watcher
	static watcherCount = 0
	subs: { [key: number]: Watcher } = {}
	depend() {
		if (Dep.target) {
			this.subs[Dep.target.id] = Dep.target
		}
	}
	notify() {
		const oldSubs = this.subs
		this.subs = {}
		for (const key in oldSubs) {
			oldSubs[key].update()
		}
	}
}

export type ShouldChange<T> = (a: T, b: T) => boolean
/**
 * 必须默认true，因为引用类似修改无法通过相等判断
 * @param a 
 * @param b 
 * @returns 
 */
export const alawaysChange: ShouldChange<any> = function (a, b) {
	return true
}
/**
 * 不相同的时候
 * @param a 
 * @param b 
 * @returns 
 */
export const notEqualChange: ShouldChange<any> = function (a, b) {
	return a != b
}
export namespace mve {
	/**只读形式*/
	export type GValue<T> = () => T
	/**值或获得值*/
	export type TValue<T> = T | GValue<T>
	/**延迟设置具体属性值 */
	export interface MDelaySet<T, A = any> {
		after(v: A, set: (v: T) => void): void
		(): A
	}
	export function delaySetAfter<T, A>(fun: () => A, after: (v: A, set: (v: T) => void) => void): MDelaySet<T, A> {
		const newFun = fun as MDelaySet<T, A>
		newFun.after = after
		return newFun
	}
	export function isDelaySet<T, A = any>(v: GValue<T> | MDelaySet<T, A>): v is MDelaySet<T, A> {
		return !!(('after' in v) && v.after)
	}
	export function isGValueOrDelaySet<T, A = any>(v: MTValue<T, A>): v is GValue<T> | MDelaySet<T, A> {
		return typeof (v) == 'function'
	}
	/**属性节点可以的类型 */
	export type MTValue<T, A = any> = TValue<T> | MDelaySet<T, A>
	/**存储器 */
	export interface Value<T> {
		(v: T): void
		(): T
	}
	/**新存储器*/
	export function valueOf<T>(v: T, shouldChange = alawaysChange): Value<T> {
		const dep = new Dep()
		return function () {
			if (arguments.length == 0) {
				dep.depend()
				return v
			} else {
				if (Dep.target) {
					throw "计算期间不允许修改"
				} else {
					const nv = arguments[0]
					if (shouldChange(v, nv)) {
						v = nv
						dep.notify()
					}
				}
			}
		}
	}
	/**
	 * 原子的值类型
	 * @param v 
	 * @param shouldChange 
	 * @returns 
	 */
	export function atomValueOf<T>(v: T, shouldChange = notEqualChange): Value<T> {
		return valueOf(v, shouldChange)
	}
	/**
	 * 转化成统一的函数
	 * @param a 
	 */
	export function valueOrCall<T>(a: TValue<T>): mve.GValue<T> {
		if (typeof (a) == 'function') {
			return a as mve.GValue<T>
		} else {
			return function () { return a }
		}
	}
	/**
	 * 重写属性值为可观察
	 * @param a 
	 * @param fun 
	 */
	export function reWriteMTValue<T, V>(a: MDelaySet<V, T> | GValue<T>, fun: (v: T) => V) {
		const after = a['after']
		const vm = function () { return fun(a()) }
		vm.after = after
		return vm
	}
	export interface ArrayModelView<T> {
		insert(index: number, row: T): void
		remove(index: number): void
		set(index: number, row: T): void
		move(oldIndex: number, newIndex: number): void
	}
	export interface CacheArrayModel<T> extends BaseReadArray<T> {
		addView(view: ArrayModelView<T>): void
		removeView(view: ArrayModelView<T>): void
	}
	export class ArrayModel<T> implements CacheArrayModel<T>, BaseArray<T>{
		private locked: boolean
		private lock() {
			if (this.locked) {
				const msg = `期间禁止操作`
				console.warn(msg, this)
				throw new Error(msg)
			}
			this.locked = true
		}
		private unlock() {
			if (this.locked) {
				this.locked = false
			} else {
				const msg = `禁止重复解锁`
				console.warn(msg, this)
				throw new Error(msg)
			}
		}
		/**
		 * 检查下标
		 * @param index 下标
		 * @param isThrow 是否作为抛出
		 * @param lessSize 必须小于size
		 */
		protected checkIndex(index: number, noThrow: boolean, lessSize = false) {
			const size = this.size()
			if (index < 0 || index > size || (lessSize && index == size)) {
				if (noThrow) {
					return false
				} else {
					const msg = `超出边界[0~${lessSize ? size - 1 : size}]`
					console.warn(msg, this)
					throw new Error(msg)
				}
			}
			return true
		}
		////////////////////////////////////////////////////////////////////
		private reload_size() {
			this.size_value(this.array.size());
		}
		private readonly views: ArrayModelView<T>[] = []
		public readonly size: mve.GValue<number>
		private readonly size_value: mve.Value<number>
		private constructor(
			private readonly array: BaseArray<T>
		) {
			this.size_value = mve.valueOf(0)
			this.size = this.size_value
			//长度是可观察的
			this.reload_size();
			this.locked = false
		}
		static of<T>(...vs: T[]) {
			return new ArrayModel(vs)
		}
		static from<T>(vs: T[], noClone?: boolean) {
			vs = noClone ? vs : vs.slice(0)
			return new ArrayModel(vs)
		}
		////////////////////////////////////////////////////////////////////
		addView(view: ArrayModelView<T>) {
			this.views.push(view);
			//自动初始化
			for (var i = 0; i < this.array.size(); i++) {
				view.insert(i, this.array.get(i))
			}
		}
		removeView(view: ArrayModelView<T>) {
			mb.Array.removeWhere(this.views, v => v == view)
		}
		////////////////////////////////////////////////////////////////////
		insert(index: number, row: T, noThrow?: boolean) {
			if (this.checkIndex(index, noThrow)) {
				this.lock()
				this.array.insert(index, row)
				this.reload_size();
				this.views.forEach(function (view) {
					view.insert(index, row)
				})
				this.unlock()
				return true
			}
			return false
		}
		remove(index: number, noThrow?: boolean) {
			if (this.checkIndex(index, noThrow, true)) {
				this.lock()
				/*更常识的使用方法*/
				const row = this.get(index);
				this.array.remove(index);
				this.reload_size()
				this.views.forEach(function (view) {
					view.remove(index);
				})
				this.unlock()
				return row;
			}
		}
		set(index: number, row: T, noThrow?: boolean) {
			if (this.checkIndex(index, noThrow, true)) {
				this.lock()
				const oldRow = this.array.set(index, row)
				this.reload_size()
				this.views.forEach(function (view) {
					view.set(index, row)
				})
				this.unlock()
				return oldRow
			}
		}
		move(oldIndex: number, newIndex: number, noThrow?: boolean) {
			if (this.checkIndex(oldIndex, noThrow, true) && this.checkIndex(newIndex, noThrow, true)) {
				this.lock()
				/**有效的方法*/
				this.array.move(oldIndex, newIndex)
				this.reload_size()
				this.views.forEach(function (view) {
					view.move(oldIndex, newIndex);
				})
				this.unlock()
				return true
			}
			return false
		}
		/**清理匹配项 */
		removeWhere(fun: (row: T, i: number) => boolean) {
			mb.Array.removeWhere(this, fun)
		}
		/**清理单纯相等的项 */
		removeEqual(row: T) {
			this.removeWhere(theRow => theRow == row)
		}
		/*多控件用array和model，单控件用包装*/
		moveToFirst(index: number) {
			this.move(index, 0);
		}
		moveToLast(index: number) {
			this.move(index, this.size() - 1);
		}
		shift() {
			return this.remove(0);
		}
		unshift(row: T) {
			return this.insert(0, row)
		}
		pop() {
			return this.remove(this.size() - 1);
		}
		push(row: T) {
			return this.insert(this.size(), row);
		}
		clear() {
			while (this.size() > 0) {
				this.pop();
			}
		}
		reset(array: T[] = []) {
			this.clear();
			for (const row of array) {
				this.push(row)
			}
		}
		//////////////////////////////////////////////////////////////////////////////
		get(i: number, noThrow?: boolean) {
			if (this.checkIndex(i, noThrow, true)) {
				//不支持响应式
				return this.array.get(i)
			}
		}
		getLast(noThrow?: boolean) {
			return this.get(this.array.size() - 1, noThrow)
		}
		findIndex(fun: (v: T, i: number) => boolean, from?: number): number {
			const size = this.size()
			for (let i = from || 0; i < size; i++) {
				const row = this.get(i)
				if (fun(row, i)) {
					return i
				}
			}
			return -1
		}
		forEach(fun: (row: T, i: number) => void) {
			const size = this.size()
			for (let i = 0; i < size; i++) {
				fun(this.get(i), i)
			}
		}
		map<V>(fun: (row: T, i: number) => V) {
			const vs: V[] = []
			const size = this.size()
			for (let i = 0; i < size; i++) {
				vs.push(fun(this.get(i), i))
			}
			return vs
		}
		filter(fun: (row: T, i: number) => boolean) {
			const vs: T[] = []
			const size = this.size()
			for (let i = 0; i < size; i++) {
				const row = this.get(i)
				if (fun(row, i)) {
					vs.push(row)
				}
			}
			return vs
		}
		findRow(fun: (row: T, i: number) => boolean, from?: number) {
			const size = this.size()
			for (let i = from || 0; i < size; i++) {
				const row = this.get(i)
				if (fun(row, i)) {
					return row
				}
			}
		}
		reduce<V>(fun: (begin: V, row: T, i: number) => V, init: V) {
			return mb.Array.reduce(this, fun, init)
		}
		indexOf(row: T, from?: number) {
			return this.findIndex(theRow => theRow == row, from);
		}
		count(fun: (row: T, i: number) => boolean) {
			const size = this.size()
			let count = 0
			for (let i = 0; i < size; i++) {
				const row = this.get(i)
				if (fun(row, i)) {
					count++
				}
			}
			return count
		}
		exist(fun: (row: T, i: number) => boolean) {
			const size = this.size()
			for (let i = 0; i < size; i++) {
				const row = this.get(i)
				if (fun(row, i)) {
					return true
				}
			}
			return false
		}
		all(fun: (row: T, i: number) => boolean) {
			const size = this.size()
			for (let i = 0; i < size; i++) {
				const row = this.get(i)
				if (!fun(row, i)) {
					return false
				}
			}
			return true
		}
		join(split?: string) {
			return this.map(v => v).join(split)
		}
	}
	/**
	 * @deprecated 使用ArrayModel.of
	 * @param array 
	 * @returns 
	 */
	export function arrayModelOf<T>(array: T[], noClone?: boolean) {
		return ArrayModel.from(array, noClone)
	}
	export interface LifeModel {
		Watch(exp: () => void): void
		WatchExp<A, B>(before: () => A, exp: (a: A) => B, after: (b: B) => void): void
		WatchBefore<A>(before: () => A, exp: (a: A) => void): void
		WatchAfter<B>(exp: () => B, after: (b: B) => void): void
		Cache<T>(fun: () => T, shouldChange?: ShouldChange<T>): () => T
		AtomCache<T>(fun: () => T, shouldChange?: ShouldChange<T>): () => T
		destroyList: (() => void)[]
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
export class Watcher {
	private constructor(
		private realUpdate: (it: Watcher) => void
	) {
		Dep.watcherCount++
		this.update()
	}
	static uid = 0
	id = Watcher.uid++
	private enable = true
	update() {
		if (this.enable) {
			this.realUpdate(this)
		}
	}
	disable() {
		this.enable = false
		Dep.watcherCount--
	}

	static of(exp: () => void) {
		return new Watcher(function (it) {
			Dep.target = it
			exp()
			Dep.target = null
		})
	}
	static ofExp<A, B>(before: () => A, exp: (a: A) => B, after: (b: B) => void) {
		return new Watcher(function (it) {
			const a = before()
			Dep.target = it
			const b = exp(a)
			Dep.target = null
			after(b)
		})
	}
	static ofBefore<A, B>(before: () => A, exp: (a: A) => void) {
		return new Watcher(function (it) {
			const a = before()
			Dep.target = it
			exp(a)
			Dep.target = null
		})
	}
	static ofAfter<B>(exp: () => B, after: (b: B) => void) {
		return new Watcher(function (it) {
			Dep.target = it
			const b = exp()
			Dep.target = null
			after(b)
		})
	}
}
class LifeModelImpl implements mve.LifeModel {
	destroyList = []
	private pool: Watcher[] = []
	Watch(exp) {
		this.pool.push(Watcher.of(exp))
	}
	WatchExp(before, exp, after) {
		this.pool.push(Watcher.ofExp(before, exp, after))
	}
	WatchBefore(before, exp) {
		this.pool.push(Watcher.ofBefore(before, exp))
	}
	WatchAfter(exp, after) {
		this.pool.push(Watcher.ofAfter(exp, after))
	}
	Cache(fun, shouldChange = alawaysChange) {
		const dep = new Dep()
		let cache
		this.Watch(function () {
			const nv = fun()
			if (shouldChange(cache, nv)) {
				cache = nv
				dep.notify()
			}
		})
		return function () {
			dep.depend()
			return cache
		}
	}
	AtomCache(fun, shouldChange = notEqualChange) {
		return this.Cache(fun, shouldChange)
	}
	destroy() {
		while (this.pool.length > 0) {
			this.pool.pop().disable()
		}
		for (let destroy of this.destroyList) {
			destroy()
		}
	}
}
export function newLifeModel(): {
	me: mve.LifeModel,
	destroy(): void
} {
	const lm = new LifeModelImpl()
	return {
		me: lm,
		destroy() {
			lm.destroy()
		}
	}
}
export type LifeModelReturn = ReturnType<typeof newLifeModel>

/////////////////////////////////////////////////////////////////////////////////////////////////////////
export type EmptyFun = () => any
export function orRun<T>(v?: (() => T) | void, def?: T): T | void {
	if (v) {
		return v()
	}
	return def
}
export type InitResult = void | EmptyFun
export interface BuildResult {
	(): InitResult
}
/**
 * 列表初始化
 * @param vs 
 * @param initV 
 * @returns 
 */
export function arrayInit<T>(vs: T[], initV: (v: T) => InitResult): InitResult {
	const size = vs.length
	const destroys: EmptyFun[] = []
	for (let i = 0; i < size; i++) {
		const destroy = initV(vs[i])
		if (destroy) {
			destroys.unshift(destroy)
		}
	}
	//返回销毁函数
	const dsize = destroys.length
	if (dsize > 1) {
		return function () {
			for (let i = 0; i < dsize; i++) {
				destroys[i]()
			}
		}
	} else
		if (dsize == 1) {
			return destroys[0]
		}
}
/**
 * 整合成一个初始化函数
 * @param inits 
 * @returns 
 */
export function getAsOne(inits: BuildResult[]): BuildResult {
	const size = inits.length
	if (size > 1) {
		return function () {
			return arrayInit(inits, mb)
		}
	} else
		if (size == 1) {
			return inits[0]
		}
}
/**单元素的解析返回*/
export interface EOParseResult<EO> {
	init?: BuildResult,
	element: EO
}
/**
 * 一次生活
 * @param init 
 * @param nowarn 
 * @returns 
 */
export function onceLife(init: BuildResult, nowarn?: boolean) {
	const warn = !nowarn
	const self = {
		isInit: false,
		isDestroy: false,
		init() {
			if (self.isInit) {
				if (warn) {
					console.warn("禁止重复init")
				}
			} else {
				self.isInit = true
				return init()
			}
		}
	}
	return self
}

export class OnceInitDestry {
	private inited = false
	private destroyed = false
	init() {
		if (this.inited) {
			throw `禁止重复初始化`
		}
		this.inited = true
	}
	destroy() {
		if (!this.inited) {
			throw `禁止未初始化销毁`
		}
		if (this.destroyed) {
			throw `已经销毁禁止重复操作`
		}
		this.destroyed = true
	}
}